import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.Random;

/**
 * Semaphore信号量学习示例
 * 模拟停车场场景：停车场有限的停车位，多辆车同时到达
 */
public class SemaphoreExample {
    public static void main(String[] args) {
        // 创建停车场示例
        ParkingLot parkingLot = new ParkingLot(3); // 停车场有3个停车位
        
        // 创建5辆车尝试停车
        for (int i = 1; i <= 5; i++) {
            Car car = new Car(i, parkingLot);
            new Thread(car).start();
        }
        
        System.out.println("=== Semaphore停车场示例启动 ===");
        System.out.println("停车场总共有3个停车位，5辆车同时到达");
        System.out.println("观察Semaphore如何控制并发访问\n");
    }
}

/**
 * 停车场类 - 使用Semaphore控制停车位数量
 */
class ParkingLot {
    private final Semaphore semaphore; // 信号量，控制可用停车位数量
    private final int totalSpots; // 总停车位数
    
    /**
     * 构造函数
     * @param spots 停车位总数
     */
    public ParkingLot(int spots) {
        this.totalSpots = spots;
        this.semaphore = new Semaphore(spots); // 初始化信号量，许可证数量等于停车位数
    }
    
    /**
     * 尝试停车
     * @param carId 车辆ID
     * @return 是否成功停车
     */
    public boolean tryPark(int carId) {
        try {
            System.out.println("车辆" + carId + "到达停车场，寻找停车位...");
            
            // 尝试获取许可证（停车位）
            if (semaphore.tryAcquire(2, TimeUnit.SECONDS)) {
                System.out.println("✓ 车辆" + carId + "成功找到停车位！ 总停车位： " + totalSpots + "当前可用停车位：" + semaphore.availablePermits());
                return true;
            } else {
                System.out.println("✗ 车辆" + carId + "等待超时，停车场已满，离开寻找其他停车场");
                return false;
            }
        } catch (InterruptedException e) {
            System.out.println("车辆" + carId + "停车过程被中断");
            Thread.currentThread().interrupt();
            return false;
        }
    }
    
    /**
     * 离开停车场
     * @param carId 车辆ID
     */
    public void leave(int carId) {
        System.out.println("车辆" + carId + "离开停车场，释放停车位");
        semaphore.release(); // 释放许可证（停车位）
        System.out.println("当前可用停车位：" + semaphore.availablePermits());
    }
    
    /**
     * 获取当前可用停车位数量
     * @return 可用停车位数
     */
    public int getAvailableSpots() {
        return semaphore.availablePermits();
    }
}

/**
 * 车辆类 - 实现Runnable接口，模拟车辆行为
 */
class Car implements Runnable {
    private final int carId;
    private final ParkingLot parkingLot;
    private final Random random;
    
    /**
     * 构造函数
     * @param carId 车辆ID
     * @param parkingLot 停车场对象
     */
    public Car(int carId, ParkingLot parkingLot) {
        this.carId = carId;
        this.parkingLot = parkingLot;
        this.random = new Random();
    }
    
    /**
     * 车辆行为：尝试停车 -> 停留一段时间 -> 离开
     */
    @Override
    public void run() {
        try {
            // 随机延迟到达时间，模拟真实场景
            Thread.sleep(random.nextInt(1000));
            
            // 尝试停车
            if (parkingLot.tryPark(carId)) {
                // 停车成功，模拟停车时间（1-4秒）
                int parkingTime = 1000 + random.nextInt(3000);
                System.out.println("车辆" + carId + "开始停车，预计停车时间：" + parkingTime/1000 + "秒");
                Thread.sleep(parkingTime);
                
                // 离开停车场
                parkingLot.leave(carId);
            }
        } catch (InterruptedException e) {
            System.out.println("车辆" + carId + "行为被中断");
            Thread.currentThread().interrupt();
        }
    }
}

/**
 * Semaphore核心概念说明：
 * 
 * 1. 什么是Semaphore？
 *    - Semaphore是一个计数信号量，用于控制同时访问特定资源的线程数量
 *    - 它维护一个许可证集合，线程在访问资源前必须获得许可证
 * 
 * 2. 主要方法：
 *    - acquire()：获取许可证，如果没有可用许可证则阻塞等待
 *    - tryAcquire()：尝试获取许可证，立即返回结果，不阻塞
 *    - tryAcquire(timeout, unit)：在指定时间内尝试获取许可证
 *    - release()：释放许可证，增加可用许可证数量
 *    - availablePermits()：返回当前可用许可证数量
 * 
 * 3. 使用场景：
 *    - 限制对资源池的并发访问（如数据库连接池）
 *    - 控制并发线程数量
 *    - 实现生产者-消费者模式中的缓冲区控制
 * 
 * 4. 本示例演示：
 *    - 如何使用Semaphore控制资源访问数量
 *    - 公平性和非公平性的区别
 *    - 超时机制的使用
 *    - 资源的获取和释放
 */